home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1998 March
/
Macworld (1998-03) (Disk 1).dmg
/
Shareware World
/
Utilities
/
Text Processing
/
Alpha
/
Tcl
/
Modes
/
diffMode.tcl
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1997-12-10
|
27.3 KB
|
1,005 lines
|
[
TEXT/ALFA
]
## -*-Tcl-*-
# ###################################################################
# Vince's Additions - an extension package for Alpha
#
# FILE: "diffMode.tcl"
# created: 7/3/95 {11:15:02 pm}
# last update: 10/12/97 {1:57:55 pm}
# Author: Vince Darley
# E-mail: <darley@fas.harvard.edu>
# mail: Division of Engineering and Applied Sciences, Harvard University
# Oxford Street, Cambridge MA 02138, USA
# www: <http://www.fas.harvard.edu/~darley/>
#
# improvements Copyright (c) 1997 Vince Darley
#
# Description:
#
# Largely re-written Diff mode for Alpha. Still under construction,
# but already a lot better than the old one. Basic features:
#
# A 'Diff' menu, which contains commonly used options.
#
# Uses Alpha's 'marks' so that you can patch diffs back and forth
# between files without losing the correct location in the file.
# (previously if you modified one of the original windows, all line
# numbers after that would be incorrect)
#
# Limitations:
#
# Sadly a lot of Alpha's window manipulation commands only work
# on the foremost window. This means this code is slowed down a
# lot because it often has to bring a window to the front before
# reading/writing into it. There is a flag to setup a hack which
# helps with this, at the expense of colours in the windows.
#
# History:
#
# modified by rev reason
# -------- --- --- -----------
# 7/3/95 Pete? 1.0 original
# 3/9/97 VMD 2.0 much improved version
# ###################################################################
##
# Usage: diff [-#] [-abBcdefhHilnNprstTuvw] [-C lines] [-F regexp] [-I regexp]
# [-L label [-L label]] [-S file] [-D symbol] [+ignore-blank-lines]
# [+context[=lines]] [+unified[=lines]] [+ifdef=symbol]
# [+show-function-line=regexp]
# [+speed-large-files] [+ignore-matching-lines=regexp] [+new-file]
# [+initial-tab] [+starting-file=file] [+text] [+all-text] [+ascii]
# [+minimal] [+ignore-space-change] [+ed] [+reversed-ed] [+ignore-case]
# [+print] [+rcs] [+show-c-function] [+binary] [+brief] [+recursive]
# [+report-identical-files] [+expand-tabs] [+ignore-all-space]
# [+file-label=label [+file-label=label]] [+version] path1 path2
alpha::mode Diff 2.5.2 diffMenu {*.diff *.patch} {diffMenu} {
alpha::package require Alpha 7.0fc3
addMenu diffMenu •288
namespace eval compare {}
menu::insert Utils submenu 0 compare
menu::insert compare items end "windows" "files…" "directories…"
hook::register requireOpenWindowsHook [list compare windows] 2
} uninstall {
removeFile "$pkg_file"
removeFile "${HOME}:Tools:GNU Diff"
} maintainer {
"Vince Darley" darley@fas.harvard.edu <http://www.fas.harvard.edu/~darley/>
} help {file "Diff Help"}
proc diffMenu {} {}
newPref f useSophisticatedDiffMarking 1 Diff
newPref f useFastWindowSwapping 1 Diff
newPref f useMarksDontBringToFront 1 Diff
newPref f synchroniseMoveAndView 1 Diff Diff::bindUpDown
newPref f workaroundAlphaColourBug 1 Diff
newPref var linesOfContext 3 Diff
newPref var diffFlags { } Diff
newPref f convertSlashToColonInPaths 1 Diff
newPref v removeFilePrefix "" Diff
menu -n $diffMenu -p Diff::menuProc -M Diff {
"rerunDiff"
"(-"
"/<I<BpatchIntoLeftWindow"
"/<I<BpatchIntoRightWindow"
"(-"
"cleanUpAndCloseWindows"
"(-"
"locateLeftWindow"
"locateRightWindow"
"locateLeftDir"
"locateRightDir"
"parseDiffWin"
}
# bind manually due to bug
bind 0x7b <z> Diff::patchIntoLeftWindow Diff
bind 0x7c <z> Diff::patchIntoRightWindow Diff
bind 0x7b <oz> Diff::patchIntoLeftWindow Diff
bind 0x7c <oz> Diff::patchIntoRightWindow Diff
# do the rest
bind '\r' Diff::Select Diff
bind '\t' Diff::View Diff
bind Kpad. <c> Diff::Win
bind Enter {Diff::Down;Diff::Select} Diff
bind Kpad0 {Diff::Up;Diff::Select} Diff
hook::register closeHook Diff::closing Diff
hook::register openHook Diff::opening Diff
proc Diff::bindUpDown {} {
global DiffmodeVars
if $DiffmodeVars(synchroniseMoveAndView) {
catch {unbind down Diff::Down Diff}
catch {unbind up Diff::Up Diff}
bind down {Diff::Down;Diff::View} Diff
bind up {Diff::Up;Diff::View} Diff
} else {
catch {unbind down {Diff::Down;Diff::View} Diff}
catch {unbind up {Diff::Up;Diff::View} Diff}
bind down Diff::Down Diff
bind up Diff::Up Diff
}
}
Diff::bindUpDown
proc Diff::menuProc {menu item} {
Diff::$item
}
proc Diff::locateLeftWindow {} {
global Diff::1
set Diff::1 [getfile "Select your left (old) file:"]
Diff::Display Diff::1 1 0 1
Diff::setMarksUp
if [info exists Diff::1] {Diff::mark ${Diff::1} 1 ""}
Diff::diffWinFront
}
proc Diff::locateRightWindow {} {
global Diff::2
set Diff::2 [getfile "Select your right (new) file:"]
Diff::Display Diff::2 0 0 1
Diff::setMarksUp
if [info exists Diff::2] {Diff::mark ${Diff::2} 0 ""}
Diff::diffWinFront
}
proc Diff::locateLeftDir {} {
global Diff::leftDir
set Diff::leftDir [get_directory "Select your left (old) directory:"]
append Diff::leftDir :
}
proc Diff::locateRightDir {} {
global Diff::rightDir
set Diff::rightDir [get_directory "Select your right (new) directory:"]
append Diff::rightDir :
}
proc Diff::rerunDiff {} {
global diffDir
Diff::diffWinFront
killWindow
if {$diffDir} {
doTheCompare 1 {* Directory Comparison *}
} else {
Diff::files
}
}
proc Diff::cleanUpAndCloseWindows {} {
global Diff::1 Diff::2 diffDir
if ![catch {bringToFront ${Diff::1}}] {
removeAllMarks diff-*
shrinkFull
killWindow
}
if ![catch {bringToFront ${Diff::2}}] {
removeAllMarks diff-*
shrinkFull
killWindow
}
Diff::diffWinFront
killWindow
}
proc Diff::closing {{name ""}} {
global Diff::array Diff::Marked Diff::1 Diff::2
foreach var [info globals Diff::array*] {
global $var
if [array exists $var] { unset $var }
}
catch {unset Diff::Marked}
catch {unset Diff::1}
catch {unset Diff::2}
}
##
# -------------------------------------------------------------------------
#
# "Diff::opening" --
#
# This procedure is called whenever we open a diff window, whether
# a '.diff' file, or whether a window produced by this mode using
# 'doTheCompare'. We parse its contents.
# -------------------------------------------------------------------------
##
proc Diff::opening {name} {
global Diff::window DiffmodeVars Diff::leftDir Diff::rightDir
set Diff::window $name
set Diff::leftDir ""
set Diff::rightDir ""
if $DiffmodeVars(useSophisticatedDiffMarking) {
Diff::parseDiffWin
}
}
# ◊◊◊◊ Parsing diff information ◊◊◊◊ #
proc Diff::parseDiffWin {} {
Diff::diffWinFront
global diffDir Diff::window
set limit 0
set pos 0
while 1 {
set res [search -s -n -f 1 -r 1 {^(diff.*|[^- \r]+)\r} $pos]
if {$res != ""} {
set pos [expr [lindex $res 0] +1]
# if we picked up a 'diff...' line in a context diff
if {[lookAt $pos] == "i" && [lookAt [nextLineStart [lindex $res 0]]] == "*"} {
continue
}
set t [getText [lindex $res 0] [expr [lindex $res 1] -1]]
if {[regexp {^\*+$} $t]} {
set diffDir 1
# check if the file has changed
if {[string index [set tt [getText [prevLineStart $pos] $pos]] 0] != " " \
&& [lookAt [expr $pos -3]] != "-" } {
set to [lindex $tt 1]
regexp { (.*)\t} $tt "" to
set p [prevLineStart $pos]
regexp { (.*)\t} [getText [prevLineStart $p] $p] from
regsub -all "/" $from ":" from
regsub -all "/" $to ":" to
lappend got [list "diff" $from $to]
}
set from [lindex [eval getText [search -s -n -f 1 -r 1 {^\*\*\* [0-9]+,[0-9]+} $pos]] 1]
set to [lindex [eval getText [search -s -n -f 1 -r 1 {^--- [0-9]+,[0-9]+} $pos]] 1]
lappend got "$from $to"
} else {
lappend got $t
}
} else {
break
}
}
set Diff::window [win::Current]
# now stored all diff items in the list 'got'
if [info exists got] {Diff::storeMarks $got}
Diff::diffWinFront
global tileTop tileWidth tileHeight tileLeft
set top [expr $tileTop + $tileHeight - 178]
sizeWin ${Diff::window} [expr $tileWidth - 6] 178
moveWin ${Diff::window} $tileLeft $top
}
proc Diff::storeMarks {diffs} {
global Diff::1 Diff::2 Diff::array
set suff ""
foreach m $diffs {
if [regexp {^diff} $m] {
set suff "/[file tail [lindex $m end]]"
global Diff::array${suff}
continue
}
set Diff::array${suff}($m) ""
}
}
proc Diff::setMarksUp {{suff ""}} {
global Diff::array${suff}
foreach m [array names Diff::array$suff] {
set scanned [Diff::parseDiffString $m]
if {[scan $scanned "%s %d %d %d %d" \
char start1 end1 start2 end2] != 5} { error "Bad diff list!" }
if {$scanned != ""} {
set Diff::array${suff}($m) $scanned
}
}
}
proc Diff::mark {win left {suff ""}} {
global Diff::array$suff DiffmodeVars
if {$win != ""} {
# Alpha somehow remembers the last mode in which it adjusts
# the window and so forgets all the colours if we cheat the
# mode switch.
if $DiffmodeVars(workaroundAlphaColourBug) {
bringToFront $win
} else {
Diff::bringToFront $win
}
# not strictly necessary, but cleaner
removeAllMarks diff-*
if $left {
foreach m [array names Diff::array$suff] {
scan [set Diff::array${suff}($m)] "%s %d %d" char start1 end1
setNamedMark "diff-$m" $start1 $start1 $end1
}
} else {
foreach m [array names Diff::array$suff] {
scan [set Diff::array${suff}($m)] "%s %d %d %d %d" char start1 end1 start2 end2
setNamedMark "diff-$m" $start2 $start2 $end2
}
}
}
}
proc Diff::markUpWindow {diffs} {
alertnote "Currently a little obsolete; shouldn't be called!"
if [info exists Diff::1] {
Diff::bringToFront ${Diff::1}
# not strictly necessry, but cleaner
removeAllMarks diff-*
foreach m $diffs {
scan [set Diff::array($m)] "%s %d %d" char start1 end1
setNamedMark "diff-$m" $start1 $start1 $end1
}
}
if [info exists Diff::2] {
Diff::bringToFront ${Diff::2}
# not strictly necessry, but cleaner
removeAllMarks diff-*
foreach m $diffs {
scan [set Diff::array($m)] "%s %d %d %d %d" char start1 end1 start2 end2
setNamedMark "diff-$m" $start2 $start2 $end2
}
}
}
proc Diff::parseDiffString {text} {
global Diff::1 Diff::2
if {![regexp {[acd]} $text char]} {
# context sensitive
set char "c"
if {[scan $text "%d,%d %d,%d" one oned two twod] != 4} {
return
}
} else {
set res [split $text $char]
if {![scan [lindex $res 0] "%d,%d" one oned]} return
if {![scan [lindex $res 1] "%d,%d" two twod]} return
if ![info exists oned] { set oned $one }
if ![info exists twod] { set twod $two }
}
if [info exists Diff::1] {
set res [list $char [rowColToPos -w ${Diff::1} $one 0]]
if {$char != "a"} {
lappend res [rowColToPos -w ${Diff::1} [expr $oned + 1] 0]
} else {
lappend res [rowColToPos -w ${Diff::1} $oned 1]
}
} else {
set res [list $char -1 -1]
}
if [info exists Diff::2] {
lappend res [rowColToPos -w ${Diff::2} $two 0]
if {$char != "d"} {
lappend res [rowColToPos -w ${Diff::2} [expr $twod + 1] 0]]
} else {
lappend res [rowColToPos -w ${Diff::2} $twod 1]
}
} else {
lappend res -1 -1
}
return $res
}
proc Diff::parseDiffLine {text {is_pos 0}} {
if {$is_pos} {
set text [Diff::line $text]
}
return [Diff::parseDiffString $text]
}
proc Diff::line {pos {f ""}} {
global diffDir Diff::window DiffmodeVars
if $diffDir {
if {$f != ""} {upvar $f files}
if {[lookAt $pos] == "*" || [catch {search -s -f 0 -r 1 {^diff.*\r} $pos} res]} {
set p $pos
while 1 {
set res [search -s -f 0 -r 1 {^\*+\r} $p]
set p [expr [lindex $res 0] -2]
if {[lookAt [lineStart $p]] != " " && [lookAt $p] != "-"} break
}
regexp { (.*)\t} [getText [lineStart $p] $p] "" to
regexp { (.*)\t} [getText [prevLineStart $p] [lineStart $p]] "" from
if {[set pr $DiffmodeVars(removeFilePrefix)] != ""} {
regsub -all "/\./" $to "/" to
if {[string first $pr $to] == 0} {
set to [string range $to [string length $pr] end]
}
regsub -all "/\./" $from "/" from
if {[string first $pr $from] == 0} {
set from [string range $from [string length $pr] end]
}
}
set files [list $from $to]
set tfrom [lindex [eval getText [search -s -n -f 1 -r 1 {^\*\*\* [0-9]+,[0-9]+} [getPos]]] 1]
set tto [lindex [eval getText [search -s -n -f 1 -r 1 {^--- [0-9]+,[0-9]+} [getPos]]] 1]
set text "$tfrom $tto"
} else {
set llen [llength [set files [eval getText $res]]]
set files [lrange $files [expr $llen -2] end]
set text [getText [lineStart $pos] [expr [nextLineStart $pos] - 1]]
}
if $DiffmodeVars(convertSlashToColonInPaths) {
regsub -all "/" $files ":" files
}
set f [lindex $files end]
set suff "/[file tail $f]"
} else {
set suff ""
set text [getText [lineStart $pos] [expr [nextLineStart $pos] - 1]]
}
return "${text}${suff}"
}
# ◊◊◊◊ Patching routines ◊◊◊◊ #
proc Diff::patch {w1 w2 left} {
global DiffmodeVars
if {$DiffmodeVars(useSophisticatedDiffMarking)} {
Diff::patchSophisticated $w1 $w2 $left
} else {
Diff::patchOld $w1 $w2 $left
}
}
proc Diff::patchSophisticated {ww1 ww2 left} {
upvar \#0 $ww1 w1
upvar \#0 $ww2 w2
set code [Diff::line [getPos]]
global Diff::array
regexp {([^/]+)(.*)} $code "" mark suff
if ![info exists w1] { alpha::errorAlert "No such window" }
switch "[lindex [set Diff::array${suff}($mark)] 0]${left}" {
"c1" -
"c0" {
if [info exists w2] {
Diff::bringToFront ${w2}
gotoMark "diff-$mark"
set text [getSelect]
} else {
# we assume the line is selected in the diff-win
if $left {
set p [selEnd]
set e [search -s -f 1 -r 1 {^---.*$} $p]
set p [lindex $e 1]
set e [search -s -f 1 -r 1 {^[^>]} $p]
set text [getText $p [lindex $e 0]]
regsub -all "\r> " $text "\r" text
set text [string range $text 1 end]
} else {
set p [selEnd]
set e [search -s -f 1 -r 1 {^---} $p]
set text [getText $p [lindex $e 0]]
regsub -all "\r< " $text "\r" text
set text [string range $text 1 end]
}
}
Diff::bringToFront ${w1}
gotoMark "diff-$mark"
replaceText [getPos] [selEnd] $text
}
"d1" -
"a0" {
Diff::bringToFront ${w1}
gotoMark "diff-$mark"
deleteText [getPos] [selEnd]
}
"a1" -
"d0" {
if [info exists w2] {
Diff::bringToFront ${w2}
gotoMark "diff-$mark"
set text [getSelect]
} else {
# we assume the line is selected in the diff-win
if $left {
set p [selEnd]
set e [search -s -f 1 -r 1 {^---.*$} $p]
set p [lindex $e 1]
set e [search -s -f 1 -r 1 {^[^>]} $p]
set text [getText $p [lindex $e 0]]
regsub -all "\r> " $text "\r" text
set text [string range $text 1 end]
} else {
set p [selEnd]
set e [search -s -f 1 -r 1 {^---} $p]
set text [getText $p [lindex $e 0]]
regsub -all "\r< " $text "\r" text
set text [string range $text 1 end]
}
}
Diff::bringToFront ${w1}
gotoMark "diff-$mark"
nextLine
insertText -w ${w1} $text
}
}
Diff::diffWinFront
}
proc Diff::patchOld {ww1 ww2 left} {
upvar \#0 $ww1 w1
upvar \#0 $ww2 w2
set code [Diff::line [getPos]]
if {[scan [Diff::parseDiffLine $code] "%s %d %d %d %d" \
char start1 end1 start2 end2] != 5} { return }
switch $char${left} {
"c1" {
set text [getText -w ${w2} $start2 $end2]
bringToFront ${w1}
replaceText $start1 $end1 $text
}
"d1" {
bringToFront ${w1}
deleteText $start1 $end1
}
"a1" {
set text [getText -w ${w2} $start2 $end2]
set p [nextLineStart $start1]
# for some reason this single line won't work instead of the
# next two!
#select -w ${Diff::1} $p $p
bringToFront ${w1}
goto $p
insertText -w ${w1} $text
}
"c0" {
set text [getText -w ${w2} $start1 $end1]
bringToFront ${w1}
replaceText $start2 $end2 $text
}
"d0" {
set text [getText -w ${w2} $start1 $end1]
bringToFront ${w1}
goto $start2
nextLine
insertText $text
}
"a0" {
bringToFront ${w1}
deleteText $start2 $end2
}
}
message "Subsequent insertions will be screwed up"
}
# In the diff-window, 'c' = cut from left, replace with given lines,
# 'd' = delete from left, 'a' = add to left.
proc Diff::patchIntoLeftWindow {} {
Diff::patch Diff::1 Diff::2 1
}
proc Diff::patchIntoRightWindow {} {
Diff::patch Diff::2 Diff::1 0
}
# ◊◊◊◊ Main comparison routines ◊◊◊◊ #
proc Diff::files {} {
global Diff::1 Diff::2
foreach f [list ${Diff::1} ${Diff::2}] {
if {[lsearch [winNames -f] $f] >= 0} {
getWinInfo -w $f arr
if $arr(dirty) {
bringToFront $f
if {![dialog::yesno "Save this window?"]} { error "Cancel"}
save
}
}
}
# make sure newer file is on the right
if [file::secondIsOlder ${Diff::1} ${Diff::2}] {
set d ${Diff::2}
set Diff::2 ${Diff::1}
set Diff::1 $d
unset d
}
Diff::Display Diff::1 1 0 1
Diff::Display Diff::2 0 0 1
doTheCompare
}
proc compare::directories {} {
global Diff::1 Diff::2
set Diff::1 [string trimright [get_directory -p "Select 'old' dir 1:"] {:}]
set Diff::2 [string trimright [get_directory -p "Select 'new' dir 2:"] {:}]
doTheCompare 1 {* Directory Comparison *}
}
proc compare::files {} {
global Diff::1 Diff::2
set Diff::1 [getfile "Select your 'old' file:"]
set Diff::2 [getfile "Select your 'new' file:"]
Diff::files
}
proc compare::windows {} {
global tileHeight tileWidth tileTop tileLeft
global Diff::1 Diff::2
set wins [winNames -f]
if {[llength $wins] < 2} { message "Need 2 windows"; return }
set Diff::1 [lindex $wins 0]
set Diff::2 [lindex $wins 1]
Diff::files
}
##
# -------------------------------------------------------------------------
#
# "doTheCompare" --
#
# Modification of the original to optionally return the diff
# result, rather than opening it in a window
#
# Results:
#
# Returns 1 if the files are the same and 0 if they differ
#
# If the global flag returnDiff is non-zero,
# the result of the diff operation is stored in diffResult, rather
# than being opened in a window
#
# --Version--Author------------------Changes-------------------------------
# 1.0 <keleher@cs.umd.edu> original
# 1.1 <j-guyer@nwu.edu> optionally return diff result in a global
# 1.2 <j-guyer@nwu.edu> flags set if files were open before compare
# -------------------------------------------------------------------------
##
proc doTheCompare {{isdir 0} {name {* File Comparison *}} {showAlert 1}} {
global tileLeft tileTop tileWidth tileHeight DiffmodeVars
global Diff::1 Diff::2 win::Modes HOME diffDir returnDiff diffResult
global Diff::1Open Diff::2Open
global Diff::leftDir Diff::rightDir
set Diff::leftDir ""
set Diff::rightDir ""
set diffDir $isdir
message "Launching 'GNU Diff'"
launch "$HOME:Tools:GNU Diff"
message "Starting diff…"
set flags $DiffmodeVars(diffFlags)
if {$DiffmodeVars(linesOfContext) != 0} {
append flags " -C $DiffmodeVars(linesOfContext)"
}
set dtext [dosc -n "GNU Diff" -s "$flags \"[stripNameCount ${Diff::1}]\" \"[stripNameCount ${Diff::2}]\""]
message "Starting diff…done"
if {[lsearch [winNames -f] ${Diff::1}] >= 0} {
set Diff::1Open 1
} else {
set Diff::1Open 0
}
if {[lsearch [winNames -f] ${Diff::2}] >= 0} {
set Diff::2Open 1
} else {
set Diff::2Open 0
}
if {![string length $dtext]} {
if {$showAlert} {
alertnote "No difference:\r${Diff::1}\r${Diff::2}"
}
return 0
} else {
# If requested, return the diff result in diffReturn,
# rather than opening a diff window
if {[info exists returnDiff] && [expr $returnDiff != 0]} {
set diffResult $dtext
} else {
set top [expr $tileTop + $tileHeight - 178]
set n [new -n $name -g $tileLeft $top [expr $tileWidth - 6] 178 -m Diff]
insertText "\r$dtext\r"
winReadOnly
select 0 [nextLineStart 0]
Diff::opening $n
}
return 1
}
}
# ◊◊◊◊ Moving around ◊◊◊◊ #
proc Diff::Up {} {
set limit 0
set res [search -s -f 0 -r 1 {^[^- \r]+\r} [expr [getPos] - 1]]
set pos [lindex $res 0]
select $pos [nextLineStart $pos]
display $pos
refresh
}
proc Diff::Down {} {
set limit 0
set res [search -s -f 1 -r 1 {^[^- \r]+\r} [expr [getPos] + 1]]
set pos [lindex $res 0]
select $pos [nextLineStart $pos]
display $pos
refresh
}
proc Diff::Select {} {
global Diff::1 Diff::2 diffDir
set text [getText [lineStart [getPos]] [expr [nextLineStart [getPos]] - 1]]
if {![regexp {[acd]} $text char]} return
set res [split $text $char]
if {![scan [lindex $res 0] "%d" one]} return
if {![scan [lindex $res 1] "%d" two]} return
if {$one == 1} {incr one}
if {$two == 1} {incr two}
if {$diffDir} {
set res [search -s -f 0 -r 1 "^diff.*\r" [getPos]]
set text [eval getText $res]
set len [llength $text]
set Diff::1 [lindex $text [expr $len - 2]]
set Diff::2 [lindex $text [expr $len - 1]]
}
Diff::Display Diff::1 1 [expr $one - 1] $diffDir
Diff::Display Diff::2 0 [expr $two - 1] $diffDir
if {$diffDir} {
catch {bringToFront ${Diff::window}}
}
}
proc Diff::Display {name left {row 0} {check 0}} {
upvar $name wname
if ![info exists wname] {
if $left {
message "Diff window for left doesn't exist"
} else {
message "Diff window for right doesn't exist"
}
return
}
if {$check} {
set geo [Diff::Geo $left]
if {[set res [lsearch [winNames -f] "$wname*"]] < 0} {
eval edit -g $geo [list $wname]
set wname [win::Current]
} else {
set wname [lindex [winNames -f] $res]
if {[getGeometry $wname] != $geo} {
sizeWin $wname [lindex $geo 2] [lindex $geo 3]
moveWin $wname [lindex $geo 0] [lindex $geo 1]
}
if {$res > 2} {
bringToFront $wname
}
}
}
display -w $wname [rowColToPos -w $wname $row 0]
}
proc Diff::viewSophisticated {} {
global Diff::1 Diff::2 diffDir DiffmodeVars Diff::Marked
global Diff::leftDir Diff::rightDir
set text [Diff::line [getPos] files]
if {$diffDir} {
set Diff::1 ${Diff::leftDir}[lindex $files 0]
if ![file exists ${Diff::1}] {
if {${Diff::leftDir} == "" && ([set res [lsearch [winNames] "[file tail ${Diff::1}]*"]] != -1)} {
set Diff::1 [lindex [winNames -f] $res]
} else {
unset Diff::1
}
} else {
if {[set res [lsearch [winNames -f] "${Diff::1}*"]] != -1} {
set Diff::1 [lindex [winNames -f] $res]
}
}
set Diff::2 ${Diff::rightDir}[lindex $files 1]
if ![file exists ${Diff::2}] {
if {${Diff::rightDir} == "" && ([set res [lsearch [winNames] "[file tail ${Diff::2}]*"]] != -1)} {
set Diff::2 [lindex [winNames -f] $res]
} else {
unset Diff::2
}
} else {
if {[set res [lsearch [winNames -f] "${Diff::2}*"]] != -1} {
set Diff::2 [lindex [winNames -f] $res]
}
}
}
regexp {([^/]+)(.*)} $text "" mark suff
if ![info exists "Diff::Marked($suff)"] {
Diff::Display Diff::1 1 0 1
Diff::Display Diff::2 0 0 1
Diff::setMarksUp $suff
if [info exists Diff::1] {
Diff::mark ${Diff::1} 1 $suff
set Diff::Marked($suff) 1
}
if [info exists Diff::2] {
Diff::mark ${Diff::2} 0 $suff
set Diff::Marked($suff) 1
}
Diff::diffWinFront
}
set text $mark
if $DiffmodeVars(useMarksDontBringToFront) {
if ![catch {getNamedMarks -w ${Diff::1}} marks] {
regexp {(.*) <[0-9]+>$} [set f ${Diff::1}] dmy f
regexp "\{ \{diff-$text\} \{[quote::Regfind $f]\} (\[0-9\]+) \[0-9\]+ (\[0-9\]+) \}" $marks dummy beg end
display -w ${Diff::1} [expr $beg > 0 ? $beg -1 : $beg]
select -w ${Diff::1} $beg $end
if {$beg > 0} {incr beg -1}
#display -w ${Diff::1} $beg
#refresh ${Diff::1}
}
if ![catch {getNamedMarks -w ${Diff::2}} marks] {
regexp {(.*) <[0-9]+>$} [set f ${Diff::2}] dmy f
regexp "\{ \{diff-$text\} \{[quote::Regfind $f]\} (\[0-9\]+) \[0-9\]+ (\[0-9\]+) \}" [getNamedMarks -w ${Diff::2}] dummy beg end
display -w ${Diff::2} [expr $beg > 0 ? $beg -1 : $beg]
select -w ${Diff::2} $beg $end
if {$beg > 0} {incr beg -1}
#display -w ${Diff::2} $beg
#refresh ${Diff::2}
}
# we need this line because of an Alpha visual bug.
# Alpha will often draw the text in the wrong window when we
# hit 'down'. It does correct itself, but it looks silly.
Diff::diffWinFront
} else {
if ![catch {Diff::bringToFront ${Diff::1}}] {
gotoMark "diff-$text"
}
if ![catch {Diff::bringToFront ${Diff::2}}] {
gotoMark "diff-$text"
}
Diff::diffWinFront
}
}
proc Diff::viewOld {} {
global Diff::1 Diff::2 diffDir
set text [Diff::line [getPos]]
if {![regexp {[acd]} $text char]} return
set res [split $text $char]
if {![scan [lindex $res 0] "%d,%d" one oned]} return
if {![scan [lindex $res 1] "%d,%d" two twod]} return
set on $one
set tw $two
if {$on == 1} {incr on}
if {$tw == 1} {incr tw}
if {![info exists oned]} {set oned $one}
if {![info exists twod]} {set twod $two}
if {$diffDir} {
set res [search -s -f 0 -r 1 "^diff.*\r" [getPos]]
set text [eval getText $res]
set Diff::1 [lindex $text 1]
set Diff::2 [lindex $text 2]
}
Diff::Sel Diff::1 [expr $on - 1] $one $oned 1
Diff::Sel Diff::2 [expr $tw - 1] $two $twod 0
set wins [lremove [lrange [winNames -f] 0 2] ${Diff::1} ${Diff::2}]
set wins [lremove -glob $wins *Comparison*]
if {$wins != ""} {
bringToFront ${Diff::1}
bringToFront ${Diff::2}
}
Diff::diffWinFront
}
proc Diff::View {} {
global DiffmodeVars
if {$DiffmodeVars(useSophisticatedDiffMarking)} {
Diff::viewSophisticated
} else {
Diff::viewOld
}
}
##
# -------------------------------------------------------------------------
#
# "Diff::Sel" --
#
# This handles a name either with or without trailing '<n>' and fixes
# the given name if it isn't right.
# -------------------------------------------------------------------------
##
proc Diff::Sel {wnamev ro row rowd left} {
global diffDir
upvar $wnamev wname
if {$diffDir} {
set geo [Diff::Geo $left]
if {[set res [lsearch [winNames -f] "$wname*"]] < 0} {
eval edit -g $geo [list $wname]
set wname [win::Current]
} else {
set wname [lindex [winNames -f] $res]
if {[getGeometry $wname] != $geo} {
sizeWin $wname [lindex $geo 2] [lindex $geo 3]
moveWin $wname [lindex $geo 0] [lindex $geo 1]
}
}
}
display -w $wname [rowColToPos -w $wname $ro 0]
select -w $wname [rowColToPos -w $wname $row 0] [rowColToPos -w $wname [expr $rowd + 1] 0]
}
# ◊◊◊◊ Utilities ◊◊◊◊ #
proc Diff::Win {} {
global win::Modes
set files [winNames -f]
set len [llength $files]
for {set i 0} {$i < $len} {incr i} {
if {[set win::Modes([lindex [winNames -f] $i])] == "Diff"} {
bringToFront [lindex [winNames] $i]
return
}
}
beep
message "No Diff window."
}
proc Diff::Geo {left} {
global tileWidth tileHeight tileTop tileLeft
set margin 4
set width [expr ($tileWidth - $margin)/2]
set height [expr $tileHeight - 200]
set hor $tileLeft
if {!$left} {incr hor [expr $width+$margin]}
return [list $hor $tileTop $width $height]
}
proc Diff::diffWinFront {} {
global Diff::window
catch {bringToFront ${Diff::window}}
}
##
# -------------------------------------------------------------------------
#
# "Diff::bringToFront" --
#
# Hack to make it quicker to switch between windows. We often want
# the 'Diff' window to be in the front all the time, but have to
# bring others to the front temporarily for manipulation. This proc
# brings a different window to the front more quickly by avoiding
# all mode-changing code. Of course you should only call this proc
# when you will _very_ soon bring a different window to the front.
# -------------------------------------------------------------------------
##
proc Diff::bringToFront {w} {
global win::Modes DiffmodeVars
if $DiffmodeVars(useFastWindowSwapping) {
set oldm [set win::Modes($w)]
set win::Modes($w) Diff
if [catch {bringToFront $w}] {
unset win::Modes($w)
beep
error "no such win"
} else {
set win::Modes($w) $oldm
}
} else {
bringToFront $w
}
}